﻿using ArtMath.Attribute;
using ArtMath.Component.Point;
using ArtMath.Core.Data;
using ArtMath.Core.Helper;
using ArtMath.Flag;
using ArtMath.Helper;
using ArtMath.PointCollection;
using ArtMath.Resource;
using System;
using System.Collections.Generic;
using System.Drawing;

namespace ArtMath.Component.ConicalSection
{
    /// <summary>
    /// 长短轴椭圆
    /// </summary>
    [Serializable]
    public class LongShortAxisEllipse : EllipseBase
    {
        public LongShortAxisEllipse(SketchPad Pad, string Name, bool Add2List = true) : base(Pad, Name, ToolTypeName.cdzty, Add2List)
        {
            InPoints = new PointBase[4];
        }

        [MultilingualCategory("Structure"), MultilingualDisplayName("{0}1", "Vertex")]
        public PointBase Point1
        {
            get { return InPoints[0]; }
            set { SetPoint(0, value); }
        }
        [MultilingualCategory("Structure"), MultilingualDisplayName("{0}2", "Vertex")]
        public PointBase Point2
        {
            get { return InPoints[1]; }
            set { SetPoint(1, value); }
        }
        [MultilingualCategory("Structure"), MultilingualDisplayName("{0}3", "Vertex")]
        public PointBase Point3
        {
            get { return InPoints[2]; }
            set { SetPoint(2, value); }
        }
        [MultilingualCategory("Structure"), MultilingualDisplayName("{0}4", "Vertex")]
        public PointBase Point4
        {
            get { return InPoints[3]; }
            set { SetPoint(3, value); }
        }
        public override int ClickTimes
        {
            get
            {
                return 3;
            }
        }
        public override PointD NewCenter
        {
            get
            {
                return (Point1.NewXY + Point2.NewXY + Point3.NewXY + Point4.NewXY) / 4;
            }
        }
        public override double NewLongAxisHalfLength
        {
            get
            {
                return Math.Max(Point1.NewXY.DistanceTo(Point2.NewXY), Point3.NewXY.DistanceTo(Point4.NewXY)) / 2;
            }
        }
        public override double NewShortAxisHalfLength
        {
            get
            {
                return Math.Min(Point1.NewXY.DistanceTo(Point2.NewXY), Point3.NewXY.DistanceTo(Point4.NewXY)) / 2;
            }
        }
        public override PointD NewPCenter
        {
            get
            {
                return (Point1.NewPxy + Point2.NewPxy + Point3.NewPxy + Point4.NewPxy) / 4;
            }
        }
        public override double NewFocusAngle
        {
            get
            {
                if (Point1.NewXY.DistanceTo(Point2.NewXY) >= Point3.NewXY.DistanceTo(Point4.NewXY))
                {
                    return Point1.NewXY.GetAngle(Point2.NewXY);
                }
                else
                {
                    return Point3.NewXY.GetAngle(Point4.NewXY);
                }
            }
        }
        public override PointCollectionBase[] GetInPointMovingRange(PointBase movePoint, Base sender = null)
        {
            switch (CountMovablePoints())
            {
                case 1:
                    if (movePoint == Point1)
                    {
                        return new PointCollectionBase[] { new DiscontinuityPoint(Point3.NewXY + Point4.NewXY - Point2.NewXY) };
                    }
                    else if (movePoint == Point2)
                    {
                        return new PointCollectionBase[] { new DiscontinuityPoint(Point3.NewXY + Point4.NewXY - Point1.NewXY) };
                    }
                    else if (movePoint == Point3)
                    {
                        return new PointCollectionBase[] { new DiscontinuityPoint(Point1.NewXY + Point2.NewXY - Point4.NewXY) };
                    }
                    else if (movePoint == Point4)
                    {
                        return new PointCollectionBase[] { new DiscontinuityPoint(Point1.NewXY + Point2.NewXY - Point3.NewXY) };
                    }
                    break;
                case 2:
                    if (movePoint == Point1)
                    {
                        if (Point2.Movable)
                        {
                            return new PointCollectionBase[] { new StraightLine((Point3.NewXY + Point4.NewXY) / 2, -1 / Point3.NewXY.GetSlope(Point4.NewXY)) };
                        }
                        else if (Point3.Movable)
                        {
                            return new PointCollectionBase[] { new PointCollection.Circle(Point4.NewXY, Point4.NewXY.DistanceTo(Point2.NewXY)) };
                        }
                        else if (Point4.Movable)
                        {
                            return new PointCollectionBase[] { new PointCollection.Circle(Point3.NewXY, Point3.NewXY.DistanceTo(Point2.NewXY)) };
                        }
                    }
                    else if (movePoint == Point2)
                    {
                        if (Point1.Movable)
                        {
                            return new PointCollectionBase[] { new StraightLine((Point3.NewXY + Point4.NewXY) / 2, -1 / Point3.NewXY.GetSlope(Point4.NewXY)) };
                        }
                        else if (Point3.Movable)
                        {
                            return new PointCollectionBase[] { new PointCollection.Circle(Point4.NewXY, Point4.NewXY.DistanceTo(Point1.NewXY)) };
                        }
                        else if (Point4.Movable)
                        {
                            return new PointCollectionBase[] { new PointCollection.Circle(Point3.NewXY, Point3.NewXY.DistanceTo(Point1.NewXY)) };
                        }
                    }
                    else if (movePoint == Point3)
                    {
                        if (Point1.Movable)
                        {
                            return new PointCollectionBase[] { new PointCollection.Circle(Point2.NewXY, Point2.NewXY.DistanceTo(Point4.NewXY)) };
                        }
                        else if (Point2.Movable)
                        {
                            return new PointCollectionBase[] { new PointCollection.Circle(Point1.NewXY, Point1.NewXY.DistanceTo(Point4.NewXY)) };
                        }
                        else if (Point4.Movable)
                        {
                            return new PointCollectionBase[] { new StraightLine((Point1.NewXY + Point2.NewXY) / 2, -1 / Point1.NewXY.GetSlope(Point2.NewXY)) };
                        }
                    }
                    else if (movePoint == Point4)
                    {
                        if (Point1.Movable)
                        {
                            return new PointCollectionBase[] { new PointCollection.Circle(Point2.NewXY, Point2.NewXY.DistanceTo(Point3.NewXY)) };
                        }
                        else if (Point2.Movable)
                        {
                            return new PointCollectionBase[] { new PointCollection.Circle(Point1.NewXY, Point1.NewXY.DistanceTo(Point3.NewXY)) };
                        }
                        else if (Point3.Movable)
                        {
                            return new PointCollectionBase[] { new StraightLine((Point1.NewXY + Point2.NewXY) / 2, -1 / Point1.NewXY.GetSlope(Point2.NewXY)) };
                        }
                    }
                    break;
            }
            return base.GetInPointMovingRange(movePoint, sender);
        }
        public override void InternalPointMove(PointBase movePoint, Base sender = null)
        {
            switch (CountMovablePoints())
            {
                case 2:
                    if (movePoint == Point1)
                    {
                        if (Point2.Movable)
                        {
                            Point2.Move(Point3.NewPxy + Point4.NewPxy - movePoint.NewPxy, true);
                        }
                        else if (Point3.Movable)
                        {
                            Point3.Move(Point2.NewPxy + movePoint.NewPxy - Point4.NewPxy, true);
                        }
                        else if (Point4.Movable)
                        {
                            Point4.Move(movePoint.NewPxy + Point2.NewPxy - Point3.NewPxy, true);
                        }
                    }
                    else if (movePoint == Point2)
                    {
                        if (Point1.Movable)
                        {
                            Point1.Move(Point3.NewPxy + Point4.NewPxy - movePoint.NewPxy, true);
                        }
                        else if (Point3.Movable)
                        {
                            Point3.Move(movePoint.NewPxy + Point1.NewPxy - Point4.NewPxy, true);
                        }
                        else if (Point4.Movable)
                        {
                            Point4.Move(Point1.NewPxy + movePoint.NewPxy - Point3.NewPxy, true);
                        }
                    }
                    else if (movePoint == Point3)
                    {
                        if (Point1.Movable)
                        {
                            Point1.Move(movePoint.NewPxy + Point4.NewPxy - Point2.NewPxy, true);
                        }
                        else if (Point2.Movable)
                        {
                            Point2.Move(movePoint.NewPxy + Point4.NewPxy - Point1.NewPxy, true);
                        }
                        else if (Point4.Movable)
                        {
                            Point4.Move(Point1.NewPxy + Point2.NewPxy - movePoint.NewPxy, true);
                        }
                    }
                    else if (movePoint == Point4)
                    {
                        if (Point1.Movable)
                        {
                            Point1.Move(movePoint.NewPxy + Point3.NewPxy - Point2.NewPxy, true);
                        }
                        else if (Point2.Movable)
                        {
                            Point2.Move(Point3.NewPxy + movePoint.NewPxy - Point1.NewPxy, true);
                        }
                        else if (Point3.Movable)
                        {
                            Point3.Move(Point2.NewPxy + Point1.NewPxy - movePoint.NewPxy, true);
                        }
                    }
                    return;
            }
            base.InternalPointMove(movePoint, sender);
        }
        public override void ComponentBuilding(Base component)
        {
            if (Point1 == null) return;
            if (OrderIndex == 0)
            {
                if (Point2 != null && Point4 == null)//Point3 == null计算的参数是错误的
                {
                    SpareCoordinate = SpareCoordinate.GetProjectivePoint(PCenter, Pad.GetVerticalLinePSlope(Point1.Pxy, Point2.Pxy));
                }
                else
                {
                    pske.Center = (Point1.Pxy + SpareCoordinate) / 2;
                    ske.Center = (Point1.ToPointD() + (Pad.PxyToXY(SpareCoordinate))) / 2;
                    ShowStatus($"{Resources.Translate("Creating")}{Resources.ColonSeparate}{Name}{Resources.LeftParenthesis}{Resources.Translate("EllipseCenter")}{Resources.ColonSeparate}{Pad.ShowPoint(Center)}）");
                    return;
                }
            }
            else
            {
                if (Point3 != null && Point2 == null)//Point2 == null不可少
                {
                    double k = Point1.ToPointD().GetSlope(Pad.PxyToXY(SpareCoordinate));
                    ske.Center = Utility.GetCrossPoint(Point1.ToPointD(), k, Point3.ToPointD(), -1 / k);
                    pske.Center = Pad.XYToPxy(Center);
                    //Pcenter = Utility.GetCrossPoint(Point1.Pxy, Point1.Pxy.GetSlope(SpareCoordinate), Point3.Pxy,
                    //    Pad.GetVerticalLinePSlope(Point1.Pxy, SpareCoordinate));
                    SpareCoordinate = 2 * PCenter - Point1.Pxy;
                    //Point2.ForceMove();
                }
                else
                {
                    ShowStatus($"{Resources.Translate("Creating")}{Resources.ColonSeparate}{Name}");
                    return;
                }
            }
            PointD p2 = Point2 == null ? Pad.PxyToXY(SpareCoordinate) : Point2.ToPointD(),
                p3 = Point3 == null ? Pad.PxyToXY(SpareCoordinate) : Point3.ToPointD(),
                p4 = 2 * Center - p3;
            LongAxisHalfLength = Center.DistanceTo(Point1.ToPointD());
            ShortAxisHalfLength = Center.DistanceTo(p3);
            if (LongAxisHalfLength < ShortAxisHalfLength)
            {
                double tmp = LongAxisHalfLength;
                LongAxisHalfLength = ShortAxisHalfLength;
                ShortAxisHalfLength = tmp;
                FocusAngle = p3.GetAngle(p4);
            }
            else
            {
                FocusAngle = Point1.ToPointD().GetAngle(p2);
            }
            //PFocus1 = Center.Offset(-RotateAngle, 半焦距长);
            //PFocus2 = Center.Offset(Math.PI - RotateAngle, 半焦距长);
            //if (Pad.Coordinate != null)
            //{
            //    PFocus1 = Pad.Coordinate.XYToPxy(PFocus1);
            //    PFocus2 = Pad.Coordinate.XYToPxy(PFocus2);
            //}
            base.ComponentBuilding(component);
        }
        public override bool CanDrawVirtual
        {
            get
            {
                if (OrderIndex == 0)
                {
                    if (Point2 != null)
                    {
                        return true;
                    }
                }
                else
                {
                    if (Point3 != null)
                    {
                        return true;
                    }
                }
                return false;
            }
        }
        public override void PaintVirtualObjects(Graphics gra)
        {
            if (CanDrawVirtual)
            {
                gra.DrawPoint(2 * PCenter - (Point3 == null ? SpareCoordinate_ : Point3.Pxy));
            }
            base.PaintVirtualObjects(gra);
        }
        protected override void ClickOrder(IList<PointCreatingArgs> args, int clickTimes, Predicate<PointCreatingArgs> act)
        {
            if (act == null) return;
            if (OrderIndex == 1)
            {
                if (!act(args[0])) return;
                if (!act(args[2])) return;
                if (!act(args[1])) return;
                if (!act(args[3])) return;
                return;
            }
            base.ClickOrder(args, clickTimes, act);
        }
        public override void CreateComponents()
        {
            if (OrderIndex == 0)
            {
                if (Point1 == null)
                {
                    Point1 = Pad.CreatePoint($"{Resources.Translate("Vertex")}1", SpareCoordinate_);
                    Pad.TrackObj = this;
                }
                else if (Point2 == null)
                {
                    Point2 = Pad.CreatePoint($"{Resources.Translate("Vertex")}2", SpareCoordinate_, true, new PointCollectionBase[] { new Universal(Point1.ToPointD()) });
                }
                else
                {
                    Point3 = Pad.CreatePoint($"{Resources.Translate("Vertex")}3", SpareCoordinate_, true, new PointCollectionBase[] { new StraightLine(Center, -1 / Point1.GetSlope(Point2)) { Exceptions = new HashSet<PointCollectionBase>() { new LineSegment(Point1.ToPointD(), Point2.ToPointD()), new PointCollection.Circle(Center, Center.DistanceTo(Point1.ToPointD())) } } });
                    Flags.ShieldCtrl(() => { Point4 = Pad.CreatePoint($"{Resources.Translate("Vertex")}4", 2 * PCenter - Point3.Pxy, false); });
                    base.CreateComponents();
                }
            }
            else
            {
                if (Point1 == null)
                {
                    Point1 = Pad.CreatePoint($"{Resources.Translate("Vertex")}1", SpareCoordinate_);
                    Pad.TrackObj = this;
                }
                else if (Point3 == null)
                {
                    Point3 = Pad.CreatePoint($"{Resources.Translate("Vertex")}3", SpareCoordinate_, true, new PointCollectionBase[] { new Universal(Point1.ToPointD()) });
                }
                else
                {
                    double k = Point1.GetSlope(Point3);
                    Point2 = Pad.CreatePoint($"{Resources.Translate("Vertex")}2", SpareCoordinate_, true, new PointCollectionBase[] { new PointCollection.Circle(Point3.ToPointD(), Point1.DistanceTo(Point3)) { Exceptions = new HashSet<PointCollectionBase>() { new StraightLine(Point3.ToPointD(), k), new StraightLine(Point3.ToPointD(), -1 / k) } } });
                    Flags.ShieldCtrl(() => { Point4 = Pad.CreatePoint($"{Resources.Translate("Vertex")}4", 2 * PCenter - Point3.Pxy, false); });
                    base.CreateComponents();
                }
            }
        }
    }
}
